package kgame5.k3d.core.obj3d.info.transform {
import kgame5.k3d.core.math.Matrix3D;
import kgame5.k3d.core.math.Vector3D;
import kgame5.k3d.core.obj3d.hardvo.HardVO;

/**
 * @author kangkai
 * 一些变换相关的信息，这个主要是变换矩阵用
 * 
 * 主要作用是存储物体的hardVO，并计算出Moc,还有一些优化信息
 * 提示，大部分游戏绕y轴转就可以了，否则可能呢绕3个轴转的有些浪费计算
 */
public class TransformInfo {
	
	//--几何信息,位置,尺寸等,重量
	public var hardVO:HardVO=new HardVO();
	
	//全局的位置，因为Model可能是在Group3D里的，但是我需要得到他在全局的位置
	//注意这个用的Mow其实是上一帧的Mow，得到的x,y,z也是上一帧的，不过这样也好，发射幻影什么的就特别方便了
	public var globalPosi:Vector3D=new Vector3D();
	
	public var ccd2:Number=0;//Camera cordinate distance2,在摄象机坐标里的距离摄像机的距离，这个是用来层级排序的
	
	//是否要排序,只有xyz变了才需要排序呢
	public var isNeedSort:Boolean=true;//
	
	//是否需要重绘,Moc是不是变了，如果变了，要刷新的
	public var isNeedRedraw:Boolean=true;
	
	//需要强制刷新//开始的时候是需要强制计算的
	public var bForceRefresh:Boolean=true;
	
	//------------------------------------------------
	
	//--矩阵:object坐标系--locale坐标系(绕自己原点旋转)---world坐标系（在世界坐标系平移）---camera摄像机坐标系
	
	private var Mol:Matrix3D=new Matrix3D();//o-l物体坐标到自己的局部坐标(旋转缩放在此生效)，就是自己的v3d_p,v3d_r起作用的范围
	public var Mow:Matrix3D=new Matrix3D();//o-w局部坐标到世界坐标的变换,public 是因为子要访问父的Mow//这个是Mow=Mol*parentNode.Mow,就是自己的局部坐标里变化再乘以父的Mow
	public var Moc:Matrix3D=new Matrix3D();//o-c局部坐标到摄象机坐标的最终变换
	
	//临时用矩阵
	private var Ms:Matrix3D=new Matrix3D();//缩放矩阵,在物体坐标系里进行缩放
	private var Mry:Matrix3D=new Matrix3D();//旋转矩阵 绕y轴旋转的
	private var Mrx:Matrix3D=new Matrix3D();//旋转矩阵 绕x轴旋转的
	private var Mrz:Matrix3D=new Matrix3D();//旋转矩阵 绕z轴旋转的
	
	private var Mr:Matrix3D=new Matrix3D();//临时的保存3个旋转的最终结果的
	
	private var M_temp:Matrix3D=new Matrix3D();//临时计算用的
	
	//排序用
	private var v3d_p_cc:Vector3D=new Vector3D();//Model3D原点在摄象机空间的坐标，这个的z就是ccz，用来排序用的
	
	//直接设置Mol(局部坐标系)的LookAt
	private var bUseLookAt:Boolean=false;//如为true，则calcFuu和calcSprite3D里的Mol不需要计算
	public function setupLookAt(eye:Vector3D,aim:Vector3D,up:Vector3D):void{
		Mol.setupLookAt(eye, aim, up);
	
		bUseLookAt=true;
		this.bForceRefresh=true;//这个一定要加上，否则设置了之后会导致其他东西不变了
	}

	//不使用优化的最质朴的变化，支持缩放和绕xyz轴的旋转，注意这个是给Mesh用的
	//这个放在这里是因为Mesh3D和Gropu3D是都用这个的
	//isParentDirty是说是否是parent的hardVO有了变化，注意这个包括摄像机是否变化
	//Mpow是parent.Mow
	public function calcMoc_Full(Mpow:Matrix3D,Mwc:Matrix3D,isCameraDirty:Boolean,isParentDirty:Boolean):void{
		
		//注意isSelfDirty一定要放在最前，否则他可能不会被执行，导致了排序的错误
		var _isDirty:Boolean=isSelfDirty()||isCameraDirty||isParentDirty|| bForceRefresh;
		bForceRefresh=false;
		isNeedRedraw=_isDirty;	
		if(_isDirty==false){
			return;
		}
		
		//----Step 1;Mol
		if(bUseLookAt){//外部直接设置了Mol的lookAt
			bUseLookAt=false;//设置为空
			this.isNeedRedraw=true;
			this.isNeedSort=true;
		}else{//常规计算Mol
			//1,scale
			Ms.setupScale(hardVO.v3d_s.x,hardVO.v3d_s.y,hardVO.v3d_s.z);
					
			//2,rotation
			if(hardVO.v3d_r.x==0&&hardVO.v3d_r.z==0){//这个是说只绕y轴有运动，因为大多数游戏饶y轴就够了，这是结合实际情况的一个优化
				Mr.setupRotate(0,1,0,hardVO.v3d_r.y);
			}else{
				Mrx.setupRotate(1,0,0,hardVO.v3d_r.x);
				Mry.setupRotate(0,1,0,hardVO.v3d_r.y);
				Mrz.setupRotate(0,0,1,hardVO.v3d_r.z);
						
				Matrix3D.SMul_MM(Mrx,Mry,M_temp);
						
				Matrix3D.SMul_MM(M_temp,Mrz,Mr);
			}
			
			//3 scale和rotation
			Matrix3D.SMul_MM(Ms,Mr,Mol);
						
			//4,translation
			Mol.setTranslation(hardVO.v3d_p.x,hardVO.v3d_p.y,hardVO.v3d_p.z);
		}
		
		//---Step 2:计算Mow=Mol*parentNode.Mlw
		Matrix3D.SMul_MM(Mol,Mpow,Mow);
		
		//---Step 3:计算Moc
		Matrix3D.SMul_MM(Mow,Mwc,Moc);
		
		
		//-----------附加操作----------
		//--填充上全局坐标,因为此时Mow已经计算出来了
		globalPosi.fill(Mow.m41, Mow.m42, Mow.m43);
		
		//--记录ccd2,供层级排序用
		updateCCD2();
	}
	//计算Moc
	public function calcMoc_Sprite3D(Mpow:Matrix3D,Mwc:Matrix3D,isCameraDirty:Boolean,isParentDirty:Boolean):void{
		
		//注意isSelfDirty一定要放在最前，否则他可能不会被执行，导致了排序的错误
		var _isDirty:Boolean=isSelfDirty()||isCameraDirty||isParentDirty|| bForceRefresh;
		isNeedRedraw=_isDirty;
		bForceRefresh=false;	
		if(_isDirty==false){
			return;
		}
		
		if(bUseLookAt){//外部直接设置了Mol的lookAt
			bUseLookAt=false;//设置为空
			this.isNeedRedraw=true;
			this.isNeedSort=true;
		} else{//常规计算Mol
			//Step 1:计算Mol 缩放，位置
			Mol.identity();
			
			//设置移动
			Mol.setTranslation(hardVO.v3d_p.x,hardVO.v3d_p.y,hardVO.v3d_p.z);
		}
		
		//Step 2:计算Mow
		Matrix3D.SMul_MM(Mol,Mpow,Mow);
		
		//Step 3:计算Moc
		Matrix3D.SMul_MM(Mow,Mwc,Moc);
		
		//-----------附加操作----------
		//--填充上全局坐标,因为此时Mow已经计算出来了
		globalPosi.fill(Mow.m41, Mow.m42, Mow.m43);
		
		//--记录ccd2,供层级排序用
		updateCCD2();
	}
	
	//保持上一个posi
	private var prePosi:Vector3D=new Vector3D();
	private var preRot:Vector3D=new Vector3D();
	private var preScale:Vector3D=new Vector3D();
	
	//hardVO是否脏了
	private function isSelfDirty():Boolean{
		var bPosiDirty:Boolean= Vector3D.STestDirty(hardVO.v3d_p, prePosi);//是否变了位置
		var bRotDirty:Boolean= Vector3D.STestDirty(hardVO.v3d_r, preRot);//是否变了旋转
		var bScaleDirty:Boolean= Vector3D.STestDirty(hardVO.v3d_s, preScale);//是否变了缩放
		isNeedSort=bPosiDirty;
		return bPosiDirty||bRotDirty||bScaleDirty;
	}
	
	//保存自己的ccd2,ccd2是在world.sortCCZ的时候是使用的，目标就是按正确的层级排序
	private function updateCCD2():void{
		//T.p("--storCCZ",getDO().name);
		//!!注意这个是说从物体坐标系的原点变换到摄象机坐标的,
		v3d_p_cc.fill(Moc.m41, Moc.m42, Moc.m43);
		//T.p(v3d_p_cc);
		ccd2=v3d_p_cc.magnitude2();
		//T.p(ccz);
	}
}//end of class
}
